#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "Arbre.h"

TREE createNode(int type, int value, char* name, int line, TREE left, TREE middle, TREE right, TREE other)
{
	TREE node = (TREE)malloc(sizeof(NODE));
	if(node==NULL)
	{
		fprintf(stderr,"KO\n");
		printf("ERROR : malloc failed in createNode(...)\n");
		exit(1);
	}
	else
	{
		node->type=type;
		node->value=value;
		node->name=name;
		node->line=line;

		node->left=left;
		node->middle=middle;
		node->right=right;
		node->other=other;

		return node;
	}
}


void freeNode(TREE node)
{
	if(node!=NULL)
	{
		if(node->name!=NULL) free(node->name);

		freeNode(node->left);
		freeNode(node->middle);
		freeNode(node->right);
		freeNode(node->other);

		free(node);
	}
}

void freeTree(TREE node)
{
	if(node!=NULL)
	{
		if(node->name!=NULL) free(node->name);

		freeNode(node->left);
		freeNode(node->middle);
		freeNode(node->right);
		freeNode(node->other);
	}
}

char* humanReadableNodeType(int type)
{
	  switch(type) {

		  case AT_ID:       	return "AT_ID"; break;
		  case AT_NBPOS:    	return "AT_NBPOS"; break;
 		  case AT_NBNEG:    	return "AT_NBNEG"; break;
		  case AT_ADD:      	return "AT_ADD"; break;
		  case AT_MIN:      	return "AT_MIN"; break;
		  case AT_MUL :     	return "AT_MUL"; break;
		  case AT_OUT :     	return "AT_OUT"; break;
		  case AT_IN :      	return "AT_IN"; break;
		  case AT_AFFECTL : 	return "AT_AFFECTL"; break;
		  case AT_AFFECTR : 	return "AT_AFFECTR"; break;
		  case AT_ILISTCODE :  	return "AT_ILISTCODE"; break;
		  case AT_ILISTDECL :  	return "AT_ILISTDECL"; break;
		  case AT_MOD:      	return "AT_MOD"; break;
		  case AT_ROOT:     	return "AT_ROOT"; break;
		  case AT_MAIN :    	return "AT_OPMAIN"; break;
                  case AT_DECL :    	return "AT_DECL"; break;
		  case AT_DECLVAR : 	return "AT_DECLVAR"; break;
		  case AT_FCT :     	return "AT_FCT"; break;
		  case AT_LISTFCT : 	return "AT_LISTFCT"; break;
		  case AT_CODE:     	return "AT_CODE"; break;
 		  case AT_AND:      	return "AT_AND"; break;
		  case AT_OR:       	return "AT_OR"; break;
		  case AT_NOT:      	return "AT_NOT"; break;
		  case AT_SMALLER:      return "AT_SMALLER"; break;
		  case AT_SMALLEQ:      return "AT_SMALLEQ"; break;
                  case AT_GREATER:      return "AT_GREATER"; break;
		  case AT_GREATEQ:      return "AT_GREATEQ"; break;
		  case AT_EQUAL:        return "AT_EQUAL"; break;
		  case AT_DIV:      	return "AT_DIV"; break;
		  case AT_LISTVAR:  	return "AT_LISTVAR"; break;
 		  case AT_ARG:      	return "AT_ARG"; break;
		  case AT_LISTARG:  	return "AT_LISTARG"; break;
		  case AT_IF:       	return "AT_IF"; break;
		  case AT_WHILE:    	return "AT_WHILE"; break;
		  case AT_ALTERN:   	return "AT_ALTERN"; break;
		  case AT_LISTINT:   	return "AT_LISTINT"; break;
		  case AT_LISTBOOL:  	return "AT_LISTBOOL"; break;
		  case AT_LISTMATRIX: 	return "AT_LISTMATRIX"; break;
		  case AT_GET: 	      	return "AT_GET"; break;
                  case AT_RETURN:     	return "AT_RETURN"; break;
                  case AT_CLONE:      	return "AT_CLONE"; break;
                  case AT_SET:        	return "AT_SET"; break;
                  case AT_CREATE:       return "AT_CREATE"; break;
		  case AT_CALLFCT:	return "AT_CALLFCT"; break;
	          case AT_CALLARG:      return "AT_CALLARG"; 
                  case AT_LISTCALLARG:  return "AT_LISTCALLARG"; break;
		  case AT_BOOL:		return "AT_BOOL"; break;
		  case AT_INT:		return "AT_INT"; break;
		  case AT_MATRIX:	return "AT_MATRIX"; break;
		  case AT_ARGVARINT:	return "AT_ARGVARINT"; break;
		  case AT_ARGINT:	return "AT_ARGINT"; break;
		  case AT_ARGVARBOOL:	return "AT_ARGVARBOOL"; break;
		  case AT_ARGBOOL:	return "AT_ARGBOOL"; break;
		  case AT_ARGVARMATRIX:	return "AT_ARGVARMATRIX"; break;
		  case AT_ARGMATRIX:	return "AT_ARGMATRIX"; break;
		  default :           	return "??";
	  }
}

void printTree(TREE tree)
{
	if(tree!=NULL)
	{
		if(tree->type == AT_FCT) {
			printf("\033[41m; [%p] type=%15s, value=%d, name=%20s,line=%3d, L=%11p , M=%11p , R=%11p, O=%11p \033[0m\n", tree, humanReadableNodeType(tree->type), tree->value, tree->name, tree->line, tree->left, tree->middle, tree->right, tree->other);
		}
		else {
			printf("; [%p] type=%15s, value=%d, name=%20s,line=%3d, L=%11p , M=%11p , R=%11p, O=%11p \n", tree, humanReadableNodeType(tree->type), tree->value, tree->name, tree->line, tree->left, tree->middle, tree->right, tree->other);
		}
	printTree(tree->left);
	printTree(tree->middle);
	printTree(tree->right);
	printTree(tree->other);

	}
}


// Cette fonction permet de générer les commandes pour le programme graphviz pour y dessiner l'arbre.

//nb permet de différencier les noeuds nill sinon tous les arcs iront vers le même noeud.
void printTreeForDia(TREE tree, int nb)
{

	if (tree != NULL)
	{
		if (tree->type == AT_FCT)
		{
			printf("p%p [style=filled fillcolor=yellow, label=""%s"", shape=doubleoctagon, color=red]; \n", tree, tree->name);
			if (tree->left != NULL)
				printf("p%p -> p%p; \n", tree, tree->left);
			else {
				printf("p%p -> nil%d ; \n", tree, nb);
				printf("nil%d [shape=point]; \n", nb, tree);
			}
	
			if (tree->right != NULL)
				printf("p%p -> p%p; \n", tree, tree->right);
			else {
				printf("p%p -> nil%d ; \n", tree, nb+1);
				printf("nil%d [shape=point]; \n", nb+1, tree);
			}

			if (tree->middle != NULL)
				printf("p%p -> p%p; \n", tree, tree->middle);
			else {
				printf("p%p -> nil%d ; \n", tree, nb+2);
				printf("nil%d [shape=point]; \n", nb+2, tree);
			}

			if (tree->other != NULL)
				printf("p%p -> p%p; \n", tree, tree->other);
			else {
				printf("p%p -> nil%d ; \n", tree, nb+2);
				printf("nil%d [shape=point]; \n", nb+2, tree);
			}
						
		}
		else if (tree->type == AT_ID) {
			printf("p%p [label=\""" %s \\n %s \""", shape=ellipse];\n", tree, humanReadableNodeType(tree->type), tree->name);
		}
		else if (tree->type == AT_NBPOS) {
			printf("p%p [label=\""" %s \\n %d \""", shape=ellipse];\n", tree, humanReadableNodeType(tree->type), tree->value);
		}
		else if (tree->type == AT_NBNEG) {
			printf("p%p [label=\""" %s \\n %d \""", shape=ellipse];\n", tree, humanReadableNodeType(tree->type), tree->value);
		}
		else
		{
			printf("p%p [label=""%s"", shape=ellipse];\n", tree, humanReadableNodeType(tree->type));	
			if (tree->left != NULL)
				printf("p%p -> p%p; \n", tree, tree->left);
			/*else {
				printf("p%p -> nil%d ; \n", tree, nb);
				printf("nil%d [shape=point]; \n", nb, tree);
			}*/
		
			if (tree->right != NULL)
				printf("p%p -> p%p; \n", tree, tree->right);
			/*else {
				printf("p%p -> nil%d ; \n", tree, nb+1);
				printf("nil%d [shape=point]; \n", nb+1, tree);
			}*/
		
			if (tree->middle != NULL)
				printf("p%p -> p%p; \n", tree, tree->middle);
			/*else {
				printf("p%p -> nil%d ; \n", tree, nb+2);
				printf("nil%d [shape=point]; \n", nb+2, tree);
			}*/
		
			if (tree->other != NULL)
				printf("p%p -> p%p; \n", tree, tree->other);
			/*else {
				printf("p%p -> nil%d ; \n", tree, nb+3);
				printf("nil%d [shape=point]; \n", nb+3, tree);
			}*/
		
		}
	printTreeForDia(tree->left, nb+1);
	printTreeForDia(tree->right, nb+1);
	printTreeForDia(tree->middle, nb+1);
	printTreeForDia(tree->other, nb+1);
	}

}








